Play の Form での error の扱ひ方
Form 型を定義する
code:scala
import play.api.data.Form
import play.api.data.Forms.{mapping, nonEmptyText, optional, text}
val xxxForm: FormXxx = Form( mapping(
"a" -> nonEmptyText,
"b" -> optional(text)
)(Xxx.apply)(Xxx.unapply)
)
custom validation
view に form を設置する
code:scala
@(
action: play.api.mvc.Call, @* new と edit で使ひ分ける爲に引數で與へる *@
button: String @* new と edit で使ひ分ける爲に引數で與へる *@
)(implicit req: RequestHeader, c: BaseContext)
@helper.form(action = @action) {
@CSRF.formField
@* 副作用が失敗した error を表示する *@
@if(orgGroupForm.globalError) {
@orgGroupForm.globalError.map{ _.message }
}
@for( field <- (Seq("a", "b").map { xxxForm(_) })) {
<label for="@field.id">@field.label</label>
<input type="text"
id="@field.id"
name="@field.name"
value="@field.value"
placeholder="@field.label" />
@* validation error を表示する *@
@orgGroupForm.error(field.label).map{ _.message }
}
<input type="submit" value="@button" />
}
controller で form action を受け附ける
code:scala
def create() = StackAction(AuthorityKey -> normalUser) { implicit req =>
xxxForm
.bindFromRequest()
.fold(
formWithErrors =>
// validation error を處理する
BadRequest(views.html.createXxx(formWithErrors)),
xxx =>
Try { Xxx.insertEntity(xxx) }
.fold(
// 副作用に失敗した場合を處理する
BadRequest(
views.html.createXxx(
xxxForm
.fill(xxx)
.withGlobalError(e.getMessage())
)
),
// 成功を返す
_ => Redirect(routes.Xxx.list())
)
)
}
test を書く
code:scala
describe("Xxx#create") {
it ("Xxx を作成できる") {
val token = generateCSRFToken
route(
FakeRequest(POST, controllers.routes.Xxx.create().url)
.withFormUrlEncodedBody(
"a" -> a,
"b" -> b,
"csrfToken" -> token
)
.withSession("csrfToken" -> token)
).fold(fail()) { case res =>
status(res) shouldBe SEE_OTHER
redirectLocation(res) shouldBe Some(controllers.routes.Xxx.list().url)
}
}
it ("もにょもにょで invalid であれば BadRequest") {
val token = generateCSRFToken
route(
FakeRequest(POST, controllers.routes.Xxx.create().url)
.withFormUrlEncodedBody(
"a" -> a, // 何か error を仕込む
"b" -> b,
"csrfToken" -> token
)
.withSession("csrfToken" -> token)
).fold(fail()) { case res =>
status(res) shouldBe BAD_REQUEST
}
}
it("もにょもにょで副作用に失敗すれば BadRequest") {
// 何か失敗する條件を仕込む
val token = generateCSRFToken
route(
FakeRequest(POST, controllers.routes.Xxx.create().url)
.withFormUrlEncodedBody(
"a" -> a,
"b" -> b,
"csrfToken" -> token
)
.withSession("csrfToken" -> token)
).fold(fail()) { case res =>
status(res) shouldBe BAD_REQUEST
}
}
}